package com.svpino.netflix;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.ArrayBlockingQueue;

import oauth.signpost.OAuthConsumer;
import oauth.signpost.commonshttp.CommonsHttpOAuthConsumer;

import com.svpino.netflix.model.Item;
import com.svpino.netflix.parsers.CatalogParser;
import com.svpino.netflix.parsers.FieldParser;

public class ProxyImpl implements Proxy {

	private final OAuthConsumer oauthConsumer;
	private ArrayBlockingQueue<Long> requestTimestamps;

	public ProxyImpl(OAuthConsumer oauthConsumer) {
		this.oauthConsumer = oauthConsumer;
		this.requestTimestamps = new ArrayBlockingQueue<Long>(4);
	}

	public ProxyImpl(String consumerKey, String consumerSecret) {
		this(new CommonsHttpOAuthConsumer(consumerKey, consumerSecret));
	}

	public synchronized <T extends Item> Response request(String resource) throws Exception {
		synchronizeRequest();

		System.err.println("REQUESTED RESOURCE:" + resource);

		URL url = new URL(this.oauthConsumer.sign(version(resource)));
		// URL url = new
		// URL(this.oauthConsumer.sign(version("http://api.netflix.com/catalog/titles/movies/70011215/previews")));

		HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
		httpURLConnection.connect();
		int responseCode = httpURLConnection.getResponseCode();

		InputStream inputStream = httpURLConnection.getInputStream();
		// FileOutputStream fos = new FileOutputStream("C:\\Temp\\index.xml");
		// OutputStreamWriter osw = new OutputStreamWriter(fos);

		Writer writer = new StringWriter();
		char[] buffer = new char[1024];
		Reader reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));

		int n;
		while ((n = reader.read(buffer)) != -1) {
			writer.write(buffer, 0, n);
			// osw.write(buffer, 0, n);
		}

		String xml = writer.toString();

		System.out.println(xml);

		writer.close();
		inputStream.close();
		// osw.close();
		// fos.close();

		return new Response(responseCode, xml);
	}

	private void synchronizeRequest() {
		try {
			if (this.requestTimestamps.remainingCapacity() > 0) {
				this.requestTimestamps.put(System.currentTimeMillis());
			}
			else {

				long value = this.requestTimestamps.poll();
				long ellapsedTime = System.currentTimeMillis() - value;
				if (ellapsedTime < 1000) {
					Thread.sleep(1000 - ellapsedTime);
				}

				this.requestTimestamps.put(System.currentTimeMillis());
			}
		}
		catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private String version(String resource) {
		resource += resource.contains("?") ? "&" : "?";
		resource += "v=" + Constants.API_VERSION;

		return resource;
	}

	@Override
	public FieldParser getFieldParser() {
		return new FieldParser(this);
	}

	@Override
	public CatalogParser getCatalogParser() {
		return new CatalogParser(this);
	}

}
